﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services.Protocols;

namespace XrmLibrary.Extensions
{
    public static class ExceptionExtensions
    {
        /// <summary>
        /// Gets all of the exception details as a string.
        /// </summary>
        /// <param name="exception">The exception to get details from.</param>
        /// <returns>A string with all of the exception details.</returns>
        public static String GetExceptionDetails(this Exception exception)
        {
            StringBuilder error = new StringBuilder();
            error.AppendFormat("Exception message: {0}", exception.Message);
            exception.GetAllInnerExceptions(error, 0);
            if (exception is SoapException)
            {
                error.AppendLine(GetSoapExceptionDetails(exception));
            }
            return error.ToString();
        }

        private static String GetSoapExceptionDetails(Exception exception)
        {
            SoapException soapException = (SoapException)exception;
            String soapExceptionDetails;
            if (soapException.Detail != null)
            {
                soapExceptionDetails = String.Format("SoapException.Detail.InnerText: {0}", soapException.Detail.InnerText.StripLineBreaks());
            }
            else
            {
                soapExceptionDetails = String.Format("SoapException contains no details.");
            }
            return soapExceptionDetails;
        }

        /// <summary>
        /// Recursively gets all inner exceptions and appends them to a StringBuilder object.
        /// </summary>
        /// <param name="ex">The exception to get InnerException details from.</param>
        /// <param name="exceptionDetails">The StringBuilder object to append details to.</param>
        /// <param name="exceptionLevel">The current level in the hierarchy of exception details.</param>
        private static void GetAllInnerExceptions(this Exception ex, StringBuilder exceptionDetails, int exceptionLevel)
        {
            if (ex.InnerException == null)
            {
                return;
            }
            Exception innerException = ex.InnerException;
            exceptionDetails.AppendLineFormat("Inner exception level [{0}] start:", exceptionLevel);
            exceptionDetails.AppendLineFormat("Type: {0}", innerException.GetType().ToString());
            exceptionDetails.AppendLineFormat("Message: {0}", innerException.Message);
            if (!string.IsNullOrEmpty(ex.InnerException.StackTrace))
            {
                exceptionDetails.AppendLineFormat("Stack trace: {0}", ex.InnerException.StackTrace);
            }
            exceptionDetails.AppendLineFormat("Inner exception level [{0}] end.", exceptionLevel);
            int nextExceptionLevel = exceptionLevel + 1;
            ex.InnerException.GetAllInnerExceptions(exceptionDetails, nextExceptionLevel);
        }
    }
}
